﻿namespace Monadic
{
    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    
    public partial struct Monad<T>
    {
        private T value;

        public Monad(T value)
        {
            this.value = value;
        }     

        public Monad<TResult> Bind<TResult>(Func<T, Monad<TResult>> func)
        {
            return func(value);
        }
    }

    public static class MonadExtensions
    {
        public static Monad<TResult> Select<T, TResult>(this Monad<T> monad, 
            Func<T, TResult> selector)
        {
            //return monad.Bind(value => Monad.Create(selector(value)));
            var bind = selector.Bind<Monad<T>, Monad<TResult>, T, TResult>();
            return bind(monad);
        }

        /// <remarks>
        /// You can use the closures to jailbreak the Monad's value. This is as bad as using reflection.
        /// </remarks>
        public static T GetValue<T>(this Monad<T> monad)
        {
            T result = default(T);

            monad.Bind(value => 
            {
                result = value;
                return monad;
            });

            return result;
        } 
    }

    public static class Monad
    {
        public static Monad<T> Create<T>(T value)
        {
            return new Monad<T>(value);
        }
    }
}
